// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#pragma once

#include <stddef.h>
#include <stdint.h>

#define TC_MAX_ARG 16
#define TC_MAX_ARG_LENGTH 8  // matches vc title length

typedef struct textcon textcon_t;
typedef uint16_t vc_char_t;

inline vc_char_t vc_char_make(uint8_t ch, uint8_t fg_color, uint8_t bg_color) {
  return static_cast<vc_char_t>(ch | ((fg_color & 0xf) << 8) | ((bg_color & 0xf) << 12));
}

inline uint8_t vc_char_get_char(vc_char_t ch) { return static_cast<uint8_t>(ch & 0xff); }

inline uint8_t vc_char_get_fg_color(vc_char_t ch) { return static_cast<uint8_t>((ch >> 8) & 0xf); }

inline uint8_t vc_char_get_bg_color(vc_char_t ch) { return static_cast<uint8_t>((ch >> 12) & 0xf); }

typedef enum textcon_param {
  TC_INVALID,
  TC_SET_TITLE,
  TC_SHOW_CURSOR,
  TC_HIDE_CURSOR,
} textcon_param_t;

struct textcon {
  void (*putc)(textcon_t* tc, uint8_t c);

  // backing data
  vc_char_t* data;

  // dimensions of display
  int w;
  int h;

  // cursor position
  int x;  // 0 < x <= w; cursor may be one position beyond right edge
  int y;  // 0 < y < h

  // callbacks to update visible display
  void (*invalidate)(void* cookie, int x, int y, int w, int h);
  void (*movecursor)(void* cookie, int x, int y);
  void (*push_scrollback_line)(void* cookie, int y);
  void (*copy_lines)(void* cookie, int y_dest, int y_src, int count);
  void (*setparam)(void* cookie, int param, uint8_t* arg, size_t arglen);
  void* cookie;

  // scrolling region
  int scroll_y0;
  int scroll_y1;

  // saved cursor position
  int save_x;
  int save_y;

  uint8_t fg;
  uint8_t bg;

  uint8_t init_fg;
  uint8_t init_bg;

  // Escape sequence parameter parsing
  // Numeric arguments
  int num;         // Argument currently being read
  int argn_count;  // Number of arguments read into argn[]
  int argn[TC_MAX_ARG];
  // String argument (e.g. for console title)
  int argstr_size;  // Number of characters read into argstr[]
  uint8_t argstr[TC_MAX_ARG_LENGTH + 1];
};

void tc_init(textcon_t* tc, int w, int h, vc_char_t* data, uint8_t fg, uint8_t bg, int cursor_x,
             int cursor_y);

void tc_copy_lines(textcon_t* tc, int y_dest, int y_src, int line_count);

static inline void tc_putc(textcon_t* tc, uint8_t c) { tc->putc(tc, c); }

void tc_seth(textcon_t* tc, int h);
